﻿using HardcoreGame.Content.Items.Weapons.Summon.Sentries;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using Terraria;
using Terraria.Audio;
using Terraria.ID;
using Terraria.ModLoader;

namespace HardcoreGame.Common.Systems
{
    public class MagicMegasharkSystem : ModSystem
    {
        private const int CHECK_INTERVAL = 20;
        private const int REQUIRED_MANA_CRYSTALS = 3;
        private const float DETECTION_RANGE = 300f;
        private enum CraftingState
        {
            Idle,
            Rising,
            Orbiting,
            Converging,
            Merging,
            Complete
        }
        private class CraftingAnimation
        {
            public int minisharkIndex;
            public List<int> manaCrystalIndices;
            public Vector2 centerPosition;
            public CraftingState state = CraftingState.Rising;
            public float animationProgress = 0f;
            public float rotationAngle = 0f;
            public float targetHeight = -120f;
            public Dictionary<int, float> crystalScales = [];
            public Dictionary<int, float> crystalOrbitRadius = [];
            public Dictionary<int, float> crystalAngles = [];
            public Dictionary<int, bool> crystalConverged = [];
            public Dictionary<int, float> crystalInitialAngles = [];
            public Dictionary<int, bool> gravityDisabled = [];
            public const int TOTAL_ORBITS = 5;
        }

        private readonly List<CraftingAnimation> activeAnimations = [];
        private int checkTimer = 0;

        public override void PreUpdateWorld()
        {
            checkTimer++;
            if (checkTimer >= CHECK_INTERVAL)
            {
                checkTimer = 0;
                CheckForCrafting();
            }

            UpdateCraftingAnimations();
        }

        private void CheckForCrafting()
        {
            if (!Main.dayTime)
            {
                for (int i = 0; i < Main.maxItems; i++)
                {
                    Item item = Main.item[i];
                    if (!item.active || item.type != ItemID.Megashark)
                        continue;
                    bool hasAnimation = false;
                    foreach (var anim in activeAnimations)
                    {
                        if (anim.minisharkIndex == i)
                        {
                            hasAnimation = true;
                            break;
                        }
                    }
                    if (hasAnimation) continue;
                    int manaCrystalCount = 0;
                    List<int> nearbyCrystals = [];
                    for (int j = 0; j < Main.maxItems; j++)
                    {
                        Item crystal = Main.item[j];
                        if (!crystal.active || crystal.type != ItemID.ManaCrystal)
                            continue;
                        float distance = Vector2.Distance(item.Center, crystal.Center);
                        if (distance <= DETECTION_RANGE)
                        {
                            manaCrystalCount += crystal.stack;
                            nearbyCrystals.Add(j);
                            if (Main.netMode != NetmodeID.Server)
                            {
                                DrawConnectionEffect(item.Center, crystal.Center);
                            }
                        }
                    }
                    if (manaCrystalCount > 0 && manaCrystalCount < REQUIRED_MANA_CRYSTALS)
                    {
                        ShowProgressHint(item.Center, manaCrystalCount);
                    }
                    if (manaCrystalCount >= REQUIRED_MANA_CRYSTALS)
                    {
                        StartCraftingAnimation(i, nearbyCrystals);
                        break;
                    }
                }
            }
        }

        private void StartCraftingAnimation(int minisharkIndex, List<int> manaCrystalIndices)
        {
            Item minishark = Main.item[minisharkIndex];
            CraftingAnimation anim = new()
            {
                minisharkIndex = minisharkIndex,
                manaCrystalIndices = [.. manaCrystalIndices],
                centerPosition = minishark.Center,
                animationProgress = 0f,
                rotationAngle = 0f
            };
            float angleStep = MathHelper.TwoPi / manaCrystalIndices.Count;
            float startAngle = Main.rand.NextFloat(0, MathHelper.TwoPi);

            for (int i = 0; i < manaCrystalIndices.Count; i++)
            {
                int index = manaCrystalIndices[i];
                float angle = startAngle + i * angleStep;
                float radius = 80f + Main.rand.NextFloat(-10f, 10f);
                anim.crystalScales[index] = 1f;
                anim.crystalOrbitRadius[index] = radius;
                anim.crystalAngles[index] = angle;
                anim.crystalInitialAngles[index] = angle;
                anim.crystalConverged[index] = false;
                anim.gravityDisabled[index] = false;
            }
            ItemID.Sets.ItemNoGravity[minishark.type] = true;
            anim.gravityDisabled[minisharkIndex] = true;
            activeAnimations.Add(anim);
            SoundEngine.PlaySound(SoundID.Item104, minishark.Center);
        }

        private void UpdateCraftingAnimations()
        {
            List<CraftingAnimation> animationsToRemove = [];

            foreach (var anim in activeAnimations)
            {
                anim.animationProgress += 0.01f;
                if (anim.minisharkIndex >= Main.maxItems || !Main.item[anim.minisharkIndex].active)
                {
                    animationsToRemove.Add(anim);
                    continue;
                }

                Item minishark = Main.item[anim.minisharkIndex];
                switch (anim.state)
                {
                    case CraftingState.Rising:
                        UpdateRisingState(anim, minishark);
                        break;

                    case CraftingState.Orbiting:
                        UpdateOrbitingState(anim, minishark);
                        break;

                    case CraftingState.Converging:
                        UpdateConvergingState(anim, minishark);
                        break;

                    case CraftingState.Merging:
                        UpdateMergingState(anim, minishark);
                        break;

                    case CraftingState.Complete:
                        CompleteCrafting(anim, minishark);
                        animationsToRemove.Add(anim);
                        break;
                }
                if (anim.animationProgress >= 1f)
                {
                    anim.animationProgress = 0f;

                    switch (anim.state)
                    {
                        case CraftingState.Rising:
                            anim.state = CraftingState.Orbiting;
                            break;

                        case CraftingState.Orbiting:
                            anim.state = CraftingState.Converging;
                            break;

                        case CraftingState.Converging:
                            anim.state = CraftingState.Merging;
                            break;

                        case CraftingState.Merging:
                            anim.state = CraftingState.Complete;
                            break;
                    }
                }
            }
            foreach (var anim in animationsToRemove)
            {
                if (anim.minisharkIndex < Main.maxItems && Main.item[anim.minisharkIndex].active)
                {
                    ItemID.Sets.ItemNoGravity[Main.item[anim.minisharkIndex].type] = false;
                }

                foreach (int index in anim.manaCrystalIndices)
                {
                    if (index < Main.maxItems && Main.item[index].active)
                    {
                        ItemID.Sets.ItemNoGravity[Main.item[index].type] = false;
                    }
                }

                activeAnimations.Remove(anim);
            }
        }

        private void UpdateRisingState(CraftingAnimation anim, Item minishark)
        {
            float height = MathHelper.Lerp(0f, anim.targetHeight, anim.animationProgress);
            minishark.position.Y = anim.centerPosition.Y + height - minishark.height / 2;
            minishark.velocity = Vector2.Zero;
            foreach (int index in anim.manaCrystalIndices)
            {
                if (index >= Main.maxItems || !Main.item[index].active)
                    continue;

                Item crystal = Main.item[index];
                if (!anim.gravityDisabled.ContainsKey(index) || !anim.gravityDisabled[index])
                {
                    ItemID.Sets.ItemNoGravity[crystal.type] = true;
                    anim.gravityDisabled[index] = true;
                }
                crystal.position.Y = anim.centerPosition.Y + height - crystal.height / 2;
                crystal.velocity = Vector2.Zero;
                SpawnCrystalParticles(crystal.Center, 1);
            }
            SpawnMinisharkParticles(minishark.Center, 2);
        }

        private void UpdateOrbitingState(CraftingAnimation anim, Item minishark)
        {
            minishark.position.Y = anim.centerPosition.Y + anim.targetHeight - minishark.height / 2;
            minishark.velocity = Vector2.Zero;
            bool allOrbitsCompleted = true;
            List<int> crystalsToRemove = [];
            foreach (int index in anim.manaCrystalIndices)
            {
                if (index >= Main.maxItems || !Main.item[index].active)
                {
                    crystalsToRemove.Add(index);
                    continue;
                }
                Item crystal = Main.item[index];
                float initialAngle = anim.crystalInitialAngles[index];
                float currentAngle = anim.crystalAngles[index];
                float radius = anim.crystalOrbitRadius[index];
                crystal.position.X = minishark.Center.X + (float)Math.Cos(currentAngle) * radius - crystal.width / 2;
                crystal.position.Y = minishark.Center.Y + (float)Math.Sin(currentAngle) * radius - crystal.height / 2;
                crystal.velocity = Vector2.Zero;
                float rotationSpeed = 0.1f;
                anim.crystalAngles[index] += rotationSpeed;
                float totalRotation = currentAngle - initialAngle;
                if (totalRotation < MathHelper.TwoPi * CraftingAnimation.TOTAL_ORBITS - 0.1f)
                {
                    allOrbitsCompleted = false;
                }
                SpawnCrystalParticles(crystal.Center, 2);
            }
            foreach (int index in crystalsToRemove)
            {
                anim.manaCrystalIndices.Remove(index);
            }
            SpawnMinisharkParticles(minishark.Center, 3);
            if (allOrbitsCompleted && anim.manaCrystalIndices.Count > 0)
            {
                anim.animationProgress = 1f;
            }
        }

        private void UpdateConvergingState(CraftingAnimation anim, Item minishark)
        {
            minishark.position.Y = anim.centerPosition.Y + anim.targetHeight - minishark.height / 2;
            minishark.velocity = Vector2.Zero;
            bool allConverged = true;
            List<int> crystalsToRemove = [];
            foreach (int index in anim.manaCrystalIndices)
            {
                if (index >= Main.maxItems || !Main.item[index].active)
                {
                    crystalsToRemove.Add(index);
                    continue;
                }

                Item crystal = Main.item[index];
                Vector2 direction = minishark.Center - crystal.Center;
                float distance = direction.Length();
                float speed = 0.1f + (1f - anim.animationProgress) * 0.5f;

                if (distance > 5f)
                {
                    crystal.velocity = direction * speed;
                    allConverged = false;
                }
                else
                {
                    crystal.position = minishark.Center - new Vector2(crystal.width / 2, crystal.height / 2);
                    crystal.velocity = Vector2.Zero;
                }
                SpawnCrystalParticles(crystal.Center, 3);
            }
            foreach (int index in crystalsToRemove)
            {
                anim.manaCrystalIndices.Remove(index);
            }
            SpawnMinisharkParticles(minishark.Center, 5);
            if (allConverged && anim.manaCrystalIndices.Count > 0)
            {
                anim.animationProgress = 1f;
            }
        }

        private void UpdateMergingState(CraftingAnimation anim, Item minishark)
        {
            minishark.position.Y = anim.centerPosition.Y + anim.targetHeight - minishark.height / 2;
            minishark.velocity = Vector2.Zero;
            List<int> crystalsToRemove = [];
            foreach (int index in anim.manaCrystalIndices)
            {
                if (index >= Main.maxItems || !Main.item[index].active)
                {
                    crystalsToRemove.Add(index);
                    continue;
                }
                Item crystal = Main.item[index];
                float scale = 1f - anim.animationProgress;
                crystal.scale = scale;
                SpawnCrystalParticles(crystal.Center, 4, scale);
            }
            foreach (int index in crystalsToRemove)
            {
                anim.manaCrystalIndices.Remove(index);
            }
            SpawnMinisharkParticles(minishark.Center, 7);
            if (anim.animationProgress > 0.5f && anim.animationProgress < 0.55f)
            {
                SoundEngine.PlaySound(SoundID.Item104, minishark.Center);
            }
        }

        private static void CompleteCrafting(CraftingAnimation anim, Item minishark)
        {
            minishark.TurnToAir();
            ItemID.Sets.ItemNoGravity[minishark.type] = false;
            foreach (int index in anim.manaCrystalIndices)
            {
                if (index < Main.maxItems && Main.item[index].active)
                {
                    ItemID.Sets.ItemNoGravity[Main.item[index].type] = false;
                    Main.item[index].TurnToAir();
                }
            }
            int newItem = Item.NewItem(
                minishark.GetSource_FromThis("MagicMinisharkCraft"),
                minishark.position,
                ModContent.ItemType<MagasharkStaff>()
            );
            for (int i = 0; i < 50; i++)
            {
                Dust dust = Dust.NewDustPerfect(
                    anim.centerPosition + Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 60f),
                    DustID.MagicMirror,
                    Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 4f),
                    255,
                    Color.Cyan,
                    2.0f
                );
                dust.noGravity = true;
            }
            SoundEngine.PlaySound(SoundID.Item4, anim.centerPosition);
            if (Main.netMode != NetmodeID.SinglePlayer)
            {
                NetMessage.SendData(MessageID.SyncItem, -1, -1, null, newItem, 1f);
            }
        }

        private static void DrawConnectionEffect(Vector2 start, Vector2 end)
        {
            if (Main.netMode != NetmodeID.Server)
            {
                for (float t = 0; t < 1; t += 0.1f)
                {
                    Vector2 pos = Vector2.Lerp(start, end, t);
                    Dust dust = Dust.NewDustPerfect(
                        pos,
                        DustID.MagicMirror,
                        Vector2.Zero,
                        100,
                        Color.LightBlue,
                        0.3f
                    );
                    dust.noGravity = true;
                }
            }
        }

        private static void ShowProgressHint(Vector2 position, int crystalCount)
        {
            if (Main.GameUpdateCount % 180 == 0)
            {
                CombatText.NewText(
                    new Rectangle((int)position.X - 20, (int)position.Y - 20, 40, 40),
                    Color.Yellow,
                    $"魔力水晶: {crystalCount}/{REQUIRED_MANA_CRYSTALS}"
                );
            }
        }

        private static void SpawnCrystalParticles(Vector2 position, int count, float scale = 1f)
        {
            for (int i = 0; i < count; i++)
            {
                Dust dust = Dust.NewDustPerfect(
                    position + Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 10f) * scale,
                    DustID.MagicMirror,
                    Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 0.5f),
                    150,
                    Color.Cyan,
                    0.8f * scale
                );
                dust.noGravity = true;
            }
        }

        private static void SpawnMinisharkParticles(Vector2 position, int count)
        {
            for (int i = 0; i < count; i++)
            {
                Dust dust = Dust.NewDustPerfect(
                    position + Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 15f),
                    DustID.MagicMirror,
                    Vector2.One.RotatedByRandom(MathHelper.TwoPi) * Main.rand.NextFloat(0, 1f),
                    200,
                    Color.LightBlue,
                    1.0f
                );
                dust.noGravity = true;
            }
        }
    }
}
